package main

import (
	"fmt"
	"sync"
	"sync/atomic"
	"time"
)

//通用的并发测试的模板
//times - 循环的次数
//f - 执行的函数，函数中的参数是循环的索引
func concurrentRun(times int, f func(int)) {
	wait := sync.WaitGroup{}
	for i := 0; i < times; i++ {
		wait.Add(1)
		//这里把i当做参数传入携程函数里，如果利用闭包直接使用i会导致所有执行中的i都等于times的次数
		go func(index int) {
			f(index)
			wait.Done()
		}(i)
	}
	wait.Wait()
}

//-----------------------------------------------------

var shareInt1 int32
var shareInt2 int32

//测试atomic包的原子操作
func testAtomic() {
	wait := sync.WaitGroup{}
	for i := 0; i < 10000; i++ {
		wait.Add(1)
		go func() {
			atomic.AddInt32(&shareInt1, 1)
			shareInt2 = shareInt2 + 1
			wait.Done()
		}()
	}
	wait.Wait()
	fmt.Println(shareInt1)
	fmt.Println(shareInt2)
}

//-----------------------------------------------------

type AValue struct {
	age int
}

// 测试自定义类型的原子操作
func testAtomicValue() {
	var av atomic.Value

	av.Store(&AValue{age: 0})
	concurrentRun(10000, func(index int) {
		av.Store(&AValue{age: index})
	})

	tmp := av.Load().(*AValue)
	fmt.Println(tmp.age)
}

//-----------------------------------------------------
type Instance struct {
	age int
}

var (
	once     sync.Once
	instance *Instance
)

//利用sync包的Once来实现单例模式，Once的实现就类似Java中的双重校验的方式类似
func testSingleton() *Instance {
	once.Do(func() {
		instance = &Instance{age: 6}
	})
	return instance
}

//实现Java栅栏的效果
func testWaitGroup() {
	wait := &sync.WaitGroup{}
	wait.Add(1)

	for i := 0; i < 100; i++ {
		go func() {
			wait.Wait()
			fmt.Println("----")
		}()
	}
	time.Sleep(time.Second * 3)
	wait.Done()
	time.Sleep(time.Second * 5)

}
func main() {
	testWaitGroup()
}
